package com.kinglumi.ailighting.auth.service.auth.impl;

import com.kinglumi.ailighting.auth.base.Query;
import com.kinglumi.ailighting.auth.constant.ServiceErrorEnum;
import com.kinglumi.ailighting.auth.entity.FileInfo;
import com.kinglumi.ailighting.auth.exception.BaseBusinessException;
import com.kinglumi.ailighting.auth.exception.FileNotFoundException;
import com.kinglumi.ailighting.auth.exception.FileStorageException;
import com.kinglumi.ailighting.auth.properties.FileUploadProperties;
import com.kinglumi.ailighting.auth.service.auth.FileSystemStorageService;
import com.kinglumi.ailighting.auth.service.biz.FileInfoService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;

/**
 * @author Neo
 */
@Service
public class FileSystemStorageServiceImpl implements FileSystemStorageService {

    private final Path dirLocation;

    public static final String ONE = "1";

    @Autowired
    FileInfoService fileInfoService;


    @Autowired
    public FileSystemStorageServiceImpl(FileUploadProperties fileUploadProperties) {
        this.dirLocation = Paths.get(fileUploadProperties.getLocation())
                .toAbsolutePath()
                .normalize();
    }

    @Override
    @PostConstruct
    public void init() {
        // TODO Auto-generated method stub
        try {
            Files.createDirectories(this.dirLocation);
        } catch (Exception ex) {
            throw new BaseBusinessException(ServiceErrorEnum.NOT_CREATE_UPLOAD);
        }

    }

    @Override
    public String saveFile(MultipartFile file, HttpServletRequest request) {

        try {
            String originalFilename = file.getOriginalFilename();
            String fileName = file.getOriginalFilename();
            fileName = Optional.ofNullable(fileName).get();
            String[] fileNameArr = fileName.split("\\.");
            String fileSimpleName = fileNameArr[0] + "_" + UUID.randomUUID();
            fileName = fileSimpleName + "." + fileNameArr[1];

            String appVersion = request.getParameter("appVersion");
            appVersion = Optional.ofNullable(appVersion).get();
            appVersion = StringUtils.trimToEmpty(appVersion);

            String updateMessage = request.getParameter("updateMessage");
            updateMessage = Optional.ofNullable(updateMessage).get();
            updateMessage = StringUtils.trimToEmpty(updateMessage);

            String type = request.getParameter("type");
            type = Optional.ofNullable(type).get();
            type = StringUtils.trimToEmpty(type);

            String bluetoothType = request.getParameter("bluetoothType");

            String englishMessage = request.getParameter("englishMessage");
            englishMessage = Optional.ofNullable(englishMessage).get();
            englishMessage = StringUtils.trimToEmpty(englishMessage);

            String isForceUpdate = request.getParameter("isForceUpdate");
            isForceUpdate = Optional.ofNullable(isForceUpdate).get();
            isForceUpdate = StringUtils.trimToEmpty(isForceUpdate);

            String scope = request.getParameter("scope");

            String jsonData = request.getParameter("jsonData");

            Path dfile = this.dirLocation.resolve(fileName);
            Files.copy(file.getInputStream(), dfile, StandardCopyOption.REPLACE_EXISTING);
            //将文件信息存到数据库
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileName(originalFilename);
            fileInfo.setFileUrl(dfile.toString());
            fileInfo.setFileVersion(appVersion);
            fileInfo.setUpdateMessage(updateMessage);
            fileInfo.setType(type);
            fileInfo.setBluetoothType(bluetoothType == null ? 1 : Integer.parseInt(bluetoothType));
            fileInfo.setCreateTime(new Date());
            fileInfo.setIsForceUpdate(ONE.equals(isForceUpdate));
            fileInfo.setEnglishMessage(englishMessage);
            fileInfo.setActiveStatus(0);
            fileInfo.setScope(scope == null ? null : Integer.parseInt(scope));
            fileInfo.setJsonData(jsonData);
            fileInfoService.insertSelectiveId(fileInfo);

            return fileName;

        } catch (Exception e) {
            throw new BaseBusinessException(ServiceErrorEnum.NOT_UPLOAD_FILE);
        }

    }

    @Override
    public Resource loadFile(int id) {

        try {

            FileInfo fileInfo = fileInfoService.selectById(id);
            assert fileInfo != null;
            String fileName = fileInfo.getFileUrl().substring(fileInfo.getFileUrl().lastIndexOf("/")+1);
            System.out.println("fileName: " + fileName);

            Path file = this.dirLocation.resolve(fileName).normalize();
            Resource resource = new UrlResource(file.toUri());

            if (resource.exists() || resource.isReadable()) {
                return resource;
            } else {
                throw new BaseBusinessException(ServiceErrorEnum.NOT_FIND_FILE);
            }
        } catch (MalformedURLException e) {
            throw new BaseBusinessException(ServiceErrorEnum.NOT_DOWNLOAD_FILE);
        }
    }

    @Override
    public Resource loadNowApp(int scope){
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("type", "android");
            params.put("nowApp", true);
            params.put("scope", scope);
            Query query = new Query(params);
            List<FileInfo> fileInfos = this.fileInfoService.selectByQuery(query);
            if(null == fileInfos || fileInfos.size() == 0){
                throw new BaseBusinessException(ServiceErrorEnum.NOT_FIND_FILE);
            }else{
                FileInfo fileInfo = fileInfos.get(0);
                assert fileInfo != null;
                try {
                    copy(fileInfo.getFileUrl(), fileInfo.getFileUrl().substring(0, fileInfo.getFileUrl().lastIndexOf("/")) + "/" + fileInfo.getFileName());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("fileName: " + fileInfo.getFileName());
                Path file = this.dirLocation.resolve(fileInfo.getFileName()).normalize();
                Resource resource = new UrlResource(file.toUri());

                if (resource.exists() || resource.isReadable()) {
                    return resource;
                } else {
                    throw new BaseBusinessException(ServiceErrorEnum.NOT_FIND_FILE);
                }
            }
        }catch (MalformedURLException e) {
            throw new BaseBusinessException(ServiceErrorEnum.NOT_DOWNLOAD_FILE);
        }
    }

    private static void copy(String url1, String url2) throws Exception {
        FileInputStream in = new FileInputStream(new File(url1));
        FileOutputStream out = new FileOutputStream(new File(url2));
        byte[] buff = new byte[512];
        int n = 0;
        System.out.println("复制文件：" + "\n" + "源路径：" + url1 + "\n" + "目标路径："
                + url2);
        while ((n = in.read(buff)) != -1) {
            out.write(buff, 0, n);
        }
        out.flush();
        in.close();
        out.close();
        System.out.println("复制完成");
    }

    @Override
    public FileInfo nowApp(int scope){
        Map<String, Object> params = new HashMap<>();
        params.put("type", "android");
        params.put("nowApp", true);
        params.put("scope", scope);
        Query query = new Query(params);
        List<FileInfo> fileInfos = this.fileInfoService.selectByQuery(query);
        return fileInfos.get(0);
    }

    @Override
    public Map<String, Object> deleteDataAndFile(int id) {
        Map<String, Object> temp = new HashMap<>();
        FileInfo fileInfo = fileInfoService.selectById(id);
        String fileUrl = "";
        if (fileInfo != null) {
            fileInfoService.delete(fileInfo);
            fileUrl = fileInfo.getFileUrl();
            File file = new File(fileUrl);
            if (file.exists()) {
                file.delete();
                temp.put("result", true);
            }
//            else {
//                temp.put("result", false);
//                temp.put("message", "Could not find file");
//                throw new FileNotFoundException("Could not find file");
//            }
        } else {
            temp.put("result", false);
            temp.put("message", "Could not find file");
            throw new BaseBusinessException(ServiceErrorEnum.NOT_ID);
        }
        return temp;
    }
}
